﻿using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using OpenAi.Util.Security;
using OpenAiProxy.API.Database;
using OpenAiProxy.API.Models;
using OpenAiProxy.API.ResourceParameters;
using OpenAiProxy.API.Services;

namespace OpenAiProxy.API.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class ProxyController : ControllerBase
    {
        private readonly IConfigService _configService;
        private readonly IHttpService _httpService;
        private readonly IDbContextFactory<MySqlDbContext> _dbContextFactory;

        public ProxyController(
            IConfigService configService,
            IHttpService httpService,
            IDbContextFactory<MySqlDbContext> dbContextFactory
        )
        {
            _configService = configService;
            _httpService = httpService;
            _dbContextFactory = dbContextFactory;
        }

        /// <summary>
        /// 获取聊天补全
        /// </summary>
        [HttpGet("chat/{accountId}")]
        public async Task<IActionResult> GetChatCompletionAsync(
            [FromRoute] string accountId,
            [FromQuery] GptChatResourceParameters resourceParameters
        )
        {
            if (string.IsNullOrWhiteSpace(accountId))
            {
                return BadRequest("UserInfo requested.");
            }

            if (string.IsNullOrWhiteSpace(resourceParameters.Question))
            {
                return BadRequest("Question requested.");
            }

            //解密
            var apiUrl = Decrypt(resourceParameters.ApiUrl ?? string.Empty);
            var apiKey = Decrypt(resourceParameters.ApiKey ?? string.Empty);
            var question = Decrypt(resourceParameters.Question);
            var model = resourceParameters.Model ?? string.Empty;

            try
            {
                //1. 数据库交互
                await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
                var accountInfo = await dbContext.AccountInfos.FirstOrDefaultAsync(t => t.Id == accountId);
                if (accountInfo == null)
                {
                    return BadRequest("Invalid user.");
                }

                if (!Enum.IsDefined(typeof(DeviceType), (int)accountInfo.DeviceType))
                {
                    return BadRequest("Unsupport device.");
                }

                var type = (DeviceType)accountInfo.DeviceType;
                switch (type)
                {
                    case DeviceType.Windows:
                        var windowInfoModel =
                            await dbContext.WindowsInfos.FirstOrDefaultAsync(t => t.Id == accountInfo.DeviceId);
                        if (windowInfoModel == null)
                        {
                            return BadRequest("Invalid windows user.");
                        }

                        //更新活跃时间
                        windowInfoModel.LastActivityTime = DateTime.Now;
                        dbContext.WindowsInfos.Update(windowInfoModel);
                        await dbContext.SaveChangesAsync();
                        break;
                    case DeviceType.Browser:
                        var browserInfoModel =
                            await dbContext.BrowserInfos.FirstOrDefaultAsync(t => t.Id == accountInfo.DeviceId);
                        if (browserInfoModel == null)
                        {
                            return BadRequest("Invalid browser user.");
                        }

                        //更新活跃时间
                        browserInfoModel.LastActivityTime = DateTime.Now;
                        dbContext.BrowserInfos.Update(browserInfoModel);
                        await dbContext.SaveChangesAsync();
                        break;
                    default:
                        return BadRequest("Invalid device user.");
                }

                //2. 接口请求
                var newApiUrl = string.IsNullOrWhiteSpace(apiKey) ? _configService.DefaultApiUrl : apiUrl;
                var newApiKey = string.IsNullOrWhiteSpace(apiKey) ? _configService.DefaultApiKey : apiKey;
                var encryptedApiUrl = Encrypt(newApiUrl ?? string.Empty);
                var encryptedApiKey = Encrypt(newApiKey ?? string.Empty);
                var encryptedQuestion = Encrypt(question);
                var queryParamDictionary = new Dictionary<string, object>()
                {
                    { "ApiUrl", encryptedApiUrl },
                    { "ApiKey", encryptedApiKey },
                    { "Question", encryptedQuestion },
                    { "Model", model }
                };

                var url = $@"{_configService.WebApiUrl}/api/wrapper/chat";
                var ret = await _httpService.GetAsync(url, queryParamDictionary);

                //3. 保存查询结果
                var correctRet = ret.Item1 ? Decrypt(ret.Item2) : ret.Item2;
                var accountHistory = new AccountHistory()
                {
                    Id = $"{Guid.NewGuid()}".Replace("-", ""),
                    AccountId = accountId,
                    Question = question,
                    ApiUrl = apiUrl,
                    ApiKey = apiKey,
                    Answer = ret.Item1 ? correctRet : string.Empty,
                    ErrorMessage = ret.Item1 ? string.Empty : correctRet,
                    IsSuccess = ret.Item1 ? (byte)1 : (byte)0,
                    CreateTime = DateTime.Now
                };
                dbContext.AccountHistories.Add(accountHistory);
                await dbContext.SaveChangesAsync();

                //4. 返回结果
                if (!ret.Item1)
                {
                    var message = $"GetChatCompletion failed：{correctRet}";
                    return Problem(Encrypt(message));
                }

                return Ok(ret.Item2);
            }
            catch (Exception e)
            {
                return Problem($"GetChatCompletion exception: {e.Message}.");
            }
        }

        /// <summary>
        /// 获取文本补全
        /// </summary>
        [HttpGet("text")]
        public async Task<IActionResult> GetTextCompletionAsync()
        {
            await Task.CompletedTask;
            return Ok();
        }

        private string Encrypt(string value) =>
            SafeDataHelper.Encrypt(value, _configService.AesKey);

        private string Decrypt(string value) =>
            SafeDataHelper.Decrypt(value, _configService.AesKey);
    }
}
